<template>
  <div ref="container" class="canvas-container"></div>
  <div class="scene-controls">
    <button
      v-for="scene in sceneManager.scenes"
      :key="scene.name"
      @click="switchScene(scene.name)"
      :class="{ active: sceneManager.currentScene?.name === scene.name }"
    >
      {{ scene.displayName }}
    </button>
  </div>
  <div class="loading-overlay" :class="{ hidden: !isLoading }">
    <div class="loading-progress">
      <div class="progress-bar">
        <div class="progress-fill" :style="progressStyle"></div>
      </div>
      <div class="loading-text">加载中: {{ loadingProgress }}%</div>
      <div class="loading-details">{{ loadingDetails }}</div>
    </div>
  </div>
</template>

<script>
import { onMounted, onUnmounted, ref, reactive, computed } from 'vue';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';

// 高级场景管理器
class AdvancedSceneManager {
  constructor(renderer) {
    this.renderer = renderer;
    this.scenes = new Map();
    this.currentScene = null;
    this.sceneStack = [];
    this.resourceManager = new ResourceManager();
    this.transitionEffect = new TransitionEffect(renderer);
  }

  // 注册场景
  async registerScene(name, config) {
    const scene = {
      name,
      displayName: config.displayName,
      instance: new THREE.Scene(),
      camera: null,
      objects: new Set(),
      resources: config.resources || [],
      initialState: config.initialState || {},
      onEnter: config.onEnter,
      onExit: config.onExit,
      onUpdate: config.onUpdate,
      isLoaded: false
    };

    this.scenes.set(name, scene);

    // 预加载场景资源
    if (config.preload !== false) {
      await this.preloadSceneResources(scene);
    }

    return scene;
  }

  // 预加载场景资源
  async preloadSceneResources(scene) {
    const resources = scene.resources;
    for (const resource of resources) {
      await this.resourceManager.load(resource);
    }
    scene.isLoaded = true;
  }

  // 切换场景
  async switchTo(sceneName, transition = true) {
    const targetScene = this.scenes.get(sceneName);
    if (!targetScene) throw new Error(`Scene ${sceneName} not found`);

    const oldScene = this.currentScene;

    // 执行场景退出逻辑
    if (oldScene && oldScene.onExit) {
      await oldScene.onExit(oldScene, targetScene);
    }

    // 加载场景资源（如果未加载）
    if (!targetScene.isLoaded) {
      await this.preloadSceneResources(targetScene);
    }

    // 执行场景转场效果
    if (transition && oldScene) {
      await this.transitionEffect.perform(oldScene, targetScene);
    }

    // 执行场景进入逻辑
    if (targetScene.onEnter) {
      await targetScene.onEnter(targetScene, oldScene);
    }

    this.currentScene = targetScene;
    this.sceneStack.push(sceneName);

    return targetScene;
  }

  // 返回上一个场景
  async goBack() {
    if (this.sceneStack.length <= 1) return;

    this.sceneStack.pop();
    const previousSceneName = this.sceneStack[this.sceneStack.length - 1];
    return this.switchTo(previousSceneName, true);
  }

  // 更新当前场景
  update(deltaTime) {
    if (this.currentScene && this.currentScene.onUpdate) {
      this.currentScene.onUpdate(this.currentScene, deltaTime);
    }
  }

  // 获取场景状态
  getSceneState(sceneName) {
    const scene = this.scenes.get(sceneName);
    return scene ? scene.state : null;
  }

  // 设置场景状态
  setSceneState(sceneName, state) {
    const scene = this.scenes.get(sceneName);
    if (scene) {
      scene.state = { ...scene.state, ...state };
    }
  }
}

// 资源管理器
class ResourceManager {
  constructor() {
    this.cache = new Map();
    this.loadingQueue = [];
    this.concurrentLoads = 3;
    this.activeLoads = 0;
  }

  async load(resource) {
    const cacheKey = this.generateCacheKey(resource);

    // 检查缓存
    if (this.cache.has(cacheKey)) {
      return this.cache.get(cacheKey);
    }

    // 加入加载队列
    return new Promise((resolve, reject) => {
      this.loadingQueue.push({ resource, resolve, reject });
      this.processQueue();
    });
  }

  async processQueue() {
    if (this.activeLoads >= this.concurrentLoads || this.loadingQueue.length === 0) {
      return;
    }

    this.activeLoads++;
    const { resource, resolve, reject } = this.loadingQueue.shift();

    try {
      const result = await this.loadResource(resource);
      this.cache.set(this.generateCacheKey(resource), result);
      resolve(result);
    } catch (error) {
      reject(error);
    } finally {
      this.activeLoads--;
      this.processQueue();
    }
  }

  async loadResource(resource) {
    const loader = this.getLoader(resource.type);
    return new Promise((resolve, reject) => {
      loader.load(
        resource.url,
        (data) => resolve(data),
        (progress) => {
          // 进度回调
          if (resource.onProgress) {
            resource.onProgress(progress);
          }
        },
        (error) => reject(error)
      );
    });
  }

  getLoader(type) {
    const loaders = {
      texture: new THREE.TextureLoader(),
      gltf: new GLTFLoader(),
      cubeTexture: new THREE.CubeTextureLoader(),
      audio: new THREE.AudioLoader()
    };
    return loaders[type] || loaders.texture;
  }

  generateCacheKey(resource) {
    return `${resource.type}:${resource.url}`;
  }

  clearCache() {
    this.cache.forEach((resource, key) => {
      if (resource.dispose) {
        resource.dispose();
      }
    });
    this.cache.clear();
  }
}

// 转场效果管理器
class TransitionEffect {
  constructor(renderer) {
    this.renderer = renderer;
    this.isTransitioning = false;
  }

  async perform(fromScene, toScene) {
    this.isTransitioning = true;

    // 这里可以实现各种转场效果
    await this.fadeTransition(fromScene, toScene);

    this.isTransitioning = false;
  }

  async fadeTransition(fromScene, toScene) {
    const duration = 1000; // 1秒过渡
    const startTime = Date.now();

    // 创建过渡效果
    const fadeMaterial = new THREE.MeshBasicMaterial({
      color: 0x000000,
      transparent: true,
      opacity: 0
    });

    const fadeGeometry = new THREE.PlaneGeometry(2, 2);
    const fadeMesh = new THREE.Mesh(fadeGeometry, fadeMaterial);
    fadeMesh.renderOrder = 9999; // 确保在最上层渲染

    toScene.instance.add(fadeMesh);

    return new Promise((resolve) => {
      const animateFade = () => {
        const elapsed = Date.now() - startTime;
        const progress = Math.min(elapsed / duration, 1);

        fadeMaterial.opacity = progress;

        if (progress < 1) {
          requestAnimationFrame(animateFade);
        } else {
          toScene.instance.remove(fadeMesh);
          fadeGeometry.dispose();
          fadeMaterial.dispose();
          resolve();
        }
      };
      animateFade();
    });
  }
}

export default {
  name: 'MultiSceneDemo',
  setup() {
    const container = ref(null);
    const isLoading = ref(false);
    const loadingProgress = ref(0);
    const loadingDetails = ref('');

    const sceneManager = reactive({
      scenes: [],
      currentScene: null,
      switchScene: async (sceneName) => {
        isLoading.value = true;
        loadingDetails.value = `切换场景: ${sceneName}`;

        try {
          await sceneManager.instance.switchTo(sceneName);
        } catch (error) {
          console.error('场景切换失败:', error);
        } finally {
          isLoading.value = false;
        }
      }
    });

    let renderer, controls, clock;

    // 初始化场景
    const init = async () => {
      // 初始化渲染器
      renderer = new THREE.WebGLRenderer({ antialias: true });
      renderer.setSize(window.innerWidth, window.innerHeight);
      renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
      container.value.appendChild(renderer.domElement);

      // 初始化场景管理器
      sceneManager.instance = new AdvancedSceneManager(renderer);

      // 注册多个场景
      await registerScenes();

      // 设置初始场景
      await sceneManager.instance.switchTo('mainScene');

      // 初始化时钟
      clock = new THREE.Clock();

      // 启动渲染循环
      animate();
    };

    // 注册场景
    const registerScenes = async () => {
      // 主场景
      await sceneManager.instance.registerScene('mainScene', {
        displayName: '主场景',
        resources: [
          { type: 'texture', url: '/textures/main.jpg' }
        ],
        onEnter: async (scene) => {
          scene.camera = createCamera();
          createMainSceneContent(scene.instance);
          controls = new OrbitControls(scene.camera, renderer.domElement);
        }
      });

      // 详细场景
      await sceneManager.instance.registerScene('detailScene', {
        displayName: '详细场景',
        resources: [
          { type: 'gltf', url: '/models/detailed.glb' }
        ],
        onEnter: async (scene) => {
          scene.camera = createCamera();
          createDetailSceneContent(scene.instance);
          controls = new OrbitControls(scene.camera, renderer.domElement);
        }
      });

      // 环境场景
      await sceneManager.instance.registerScene('environmentScene', {
        displayName: '环境场景',
        preload: false, // 不预加载
        resources: [
          { type: 'cubeTexture', url: [
            '/env/px.jpg', '/env/nx.jpg',
            '/env/py.jpg', '/env/ny.jpg',
            '/env/pz.jpg', '/env/nz.jpg'
          ]}
        ],
        onEnter: async (scene) => {
          scene.camera = createCamera();
          createEnvironmentSceneContent(scene.instance);
          controls = new OrbitControls(scene.camera, renderer.domElement);
        }
      });

      sceneManager.scenes = Array.from(sceneManager.instance.scenes.values());
    };

    // 创建相机
    const createCamera = () => {
      const camera = new THREE.PerspectiveCamera(
        75,
        window.innerWidth / window.innerHeight,
        0.1,
        1000
      );
      camera.position.set(0, 5, 10);
      return camera;
    };

    // 创建场景内容
    const createMainSceneContent = (scene) => {
      // 添加基础内容
      const geometry = new THREE.BoxGeometry(2, 2, 2);
      const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
      const mesh = new THREE.Mesh(geometry, material);
      scene.add(mesh);

      // 添加灯光
      const light = new THREE.DirectionalLight(0xffffff, 1);
      light.position.set(5, 10, 5);
      scene.add(light);
      scene.add(new THREE.AmbientLight(0x404040));
    };

    const createDetailSceneContent = (scene) => {
      // 创建详细场景内容
      const geometry = new THREE.SphereGeometry(2, 32, 32);
      const material = new THREE.MeshStandardMaterial({
        color: 0xff0000,
        roughness: 0.5,
        metalness: 0.5
      });
      const mesh = new THREE.Mesh(geometry, material);
      scene.add(mesh);

      const light = new THREE.PointLight(0xffffff, 1, 100);
      light.position.set(0, 5, 5);
      scene.add(light);
    };

    const createEnvironmentSceneContent = (scene) => {
      // 创建环境场景内容
      const geometry = new THREE.TorusKnotGeometry(2, 0.5, 100, 16);
      const material = new THREE.MeshStandardMaterial({
        color: 0x0000ff,
        roughness: 0.2,
        metalness: 0.8
      });
      const mesh = new THREE.Mesh(geometry, material);
      scene.add(mesh);

      const light = new THREE.HemisphereLight(0x443333, 0x111122);
      scene.add(light);
    };

    // 动画循环
    const animate = () => {
      requestAnimationFrame(animate);

      const deltaTime = clock.getDelta();

      // 更新场景管理器
      if (sceneManager.instance) {
        sceneManager.instance.update(deltaTime);
      }

      // 渲染当前场景
      if (sceneManager.instance?.currentScene) {
        const { instance: scene, camera } = sceneManager.instance.currentScene;
        if (scene && camera) {
          renderer.render(scene, camera);
        }
      }

      // 更新控件
      if (controls) {
        controls.update();
      }
    };

    // 响应式进度条样式
    const progressStyle = computed(() => ({
      width: `${loadingProgress.value}%`
    }));

    // 资源清理
    const cleanup = () => {
      if (sceneManager.instance) {
        sceneManager.instance.resourceManager.clearCache();
      }
      if (renderer) {
        renderer.dispose();
      }
    };

    onMounted(() => {
      init();
      window.addEventListener('resize', handleResize);
    });

    onUnmounted(() => {
      cleanup();
      window.removeEventListener('resize', handleResize);
    });

    const handleResize = () => {
      if (!renderer) return;
      renderer.setSize(window.innerWidth, window.innerHeight);

      // 更新所有场景的相机
      if (sceneManager.instance) {
        for (const scene of sceneManager.instance.scenes.values()) {
          if (scene.camera) {
            scene.camera.aspect = window.innerWidth / window.innerHeight;
            scene.camera.updateProjectionMatrix();
          }
        }
      }
    };

    return {
      container,
      isLoading,
      loadingProgress,
      loadingDetails,
      sceneManager,
      progressStyle
    };
  }
};
</script>

<style scoped>
.canvas-container {
  width: 100%;
  height: 100vh;
  position: relative;
}

.scene-controls {
  position: absolute;
  bottom: 20px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 10px;
  background: rgba(0, 0, 0, 0.8);
  padding: 15px;
  border-radius: 10px;
  backdrop-filter: blur(10px);
}

.scene-controls button {
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
  background: rgba(255, 255, 255, 0.1);
  color: white;
  cursor: pointer;
  transition: all 0.3s ease;
}

.scene-controls button:hover {
  background: rgba(255, 255, 255, 0.2);
}

.scene-controls button.active {
  background: #007bff;
  box-shadow: 0 0 10px rgba(0, 123, 255, 0.5);
}

.loading-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.8);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
  transition: opacity 0.3s ease;
}

.loading-overlay.hidden {
  opacity: 0;
  pointer-events: none;
}

.loading-progress {
  width: 300px;
  text-align: center;
}

.progress-bar {
  width: 100%;
  height: 4px;
  background: rgba(255, 255, 255, 0.2);
  border-radius: 2px;
  overflow: hidden;
  margin-bottom: 10px;
}

.progress-fill {
  height: 100%;
  background: #007bff;
  transition: width 0.3s ease;
  border-radius: 2px;
}

.loading-text {
  color: white;
  font-size: 16px;
  margin-bottom: 5px;
}

.loading-details {
  color: rgba(255, 255, 255, 0.7);
  font-size: 12px;
}
</style>
